package org.eclipse.epsilon.emc.jdt2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;

public class SearchUtil {

	public static Collection<?> search(String type, ASTReflection astModel,
			List<IJavaProject> javaProjects, String keyWord, boolean isSource) {
		System.out.println("Search: method");
		// final QuickList resultList = new QuickList(type, astModel,
		// javaProjects, true);

		// The return list of results
		final ArrayList<Object> results = new ArrayList<Object>();
		final ArrayList<ICompilationUnit> compilationUnits = new ArrayList<ICompilationUnit>();
		final ArrayList<String> names = new ArrayList<String>();
		boolean isAST = true;
		boolean isSize = false;

		IJavaProject[] javaProjectsA = javaProjects
				.toArray(new IJavaProject[javaProjects.size()]);

		SearchPattern pattern = null;
		SearchRequestor requestor = null;

		// create search scope with the packages above and set only search
		// for source folders
		IJavaSearchScope scope;
		if (isSource) {
			scope = SearchEngine.createJavaSearchScope(javaProjectsA,
					IJavaSearchScope.SOURCES);
		} else {
			System.out.println("abc");
			scope = SearchEngine.createJavaSearchScope(javaProjectsA);
		}

		System.out.println("check type");
		if (type.equals(JdtModel.PACKAGE_DEC)) {
			isAST = false;
			// create search pattern for declarations of packages
			pattern = SearchPattern.createPattern(keyWord,
					IJavaSearchConstants.PACKAGE,
					IJavaSearchConstants.DECLARATIONS,
					SearchPattern.R_PATTERN_MATCH
							| SearchPattern.R_CASE_SENSITIVE);

			// create search requestor
			requestor = new SearchRequestor() {
				@Override
				public void acceptSearchMatch(SearchMatch match) {
					// Save the SearchMatch somewhere
					Object object = match.getElement();

					// System.out.println(object.getClass());

					IPackageFragment temp = null;
					if (object instanceof IPackageFragment) {
						temp = (IPackageFragment) object;
						// System.out.println(temp.getElementName());
						results.add(temp);
					}
				}
			};

		} else if (type.equals(JdtModel.TYPE_DEC)) {
			System.out.println("search type declaration: " + keyWord);
			if (keyWord.equals("*")) {
				try {
					return astModel.getAllOfKind(type);
				} catch (JavaModelException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else {
				// ArrayList<Object> tmpList = new ArrayList<Object>();
				// final ArrayList<ICompilationUnit> compilationUnits = new
				// ArrayList<ICompilationUnit>();

				if (keyWord.equals("_size_")) {
					keyWord = "*";
					isAST = false;
					// create search requestor
					requestor = new SearchRequestor() {
						@Override
						public void acceptSearchMatch(SearchMatch match) {
							// Save the SearchMatch somewhere
							Object object = match.getElement();
							// System.out.println(object.getClass());
							IType temp = null;
							if (object instanceof IType) {
								temp = (IType) object;
								System.out.println(temp.getCompilationUnit()
										.getElementName());

								results.add(temp);
							}
						}
					};
				} else {
					// create search requestor
					requestor = new SearchRequestor() {
						@Override
						public void acceptSearchMatch(SearchMatch match) {
							// Save the SearchMatch somewhere
							Object object = match.getElement();
							// System.out.println(object.getClass());
							IType temp = null;
							if (object instanceof IType) {
								temp = (IType) object;
								System.out.println(temp.getCompilationUnit()
										.getElementName());
								// System.out.println(temp.getElementName());

								compilationUnits.add(temp.getCompilationUnit());
								names.add(temp.getElementName());
							}
						}
					};
				}

				// create search pattern for declarations of
				pattern = SearchPattern.createPattern(keyWord,
						IJavaSearchConstants.TYPE,
						IJavaSearchConstants.DECLARATIONS,
						SearchPattern.R_PATTERN_MATCH
								| SearchPattern.R_CASE_SENSITIVE);

				// create the search engine and start to search
				// SearchEngine engine = new SearchEngine();
				// try {
				// engine.search(pattern,
				// new SearchParticipant[] { SearchEngine
				// .getDefaultSearchParticipant() }, scope,
				// requestor, null);
				// } catch (CoreException e) {
				// // TODO Auto-generated catch block
				// e.printStackTrace();
				// }
				//
				// // select the ast node of the types
				// try {
				// results.addAll(astModel.select(compilationUnits, type,
				// keyWord));
				// } catch (JavaModelException e) {
				// // TODO Auto-generated catch block
				// e.printStackTrace();
				// }
			}
		} else if (type.equals(JdtModel.METHOD_DEC)) {
			System.out.println("search method declaration: " + keyWord);
			if (keyWord.equals("*")) {
				try {
					return astModel.getAllOfKind(type);
				} catch (JavaModelException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else {
				// ArrayList<Object> tmpList = new ArrayList<Object>();
				// = new ArrayList<ICompilationUnit>();

				// create search pattern for declarations of packages
				pattern = SearchPattern.createPattern(keyWord,
						IJavaSearchConstants.METHOD,
						IJavaSearchConstants.DECLARATIONS,
						SearchPattern.R_PATTERN_MATCH
								| SearchPattern.R_CASE_SENSITIVE);

				// create search requestor
				requestor = new SearchRequestor() {
					@Override
					public void acceptSearchMatch(SearchMatch match) {
						// Save the SearchMatch somewhere
						Object object = match.getElement();
						// System.out.println(object.getClass());
						IMethod temp = null;
						if (object instanceof IMethod) {
							temp = (IMethod) object;
							System.out.println(temp.getCompilationUnit()
									.getElementName()+"|"+temp.getElementName());

							// avoid duplicate
							if (!compilationUnits.contains(temp
									.getCompilationUnit())) {
								compilationUnits.add(temp.getCompilationUnit());
								names.add(temp.getElementName());
							}
						}
					}
				};

				// create the search engine and start to search
				// SearchEngine engine = new SearchEngine();
				// try {
				// engine.search(pattern,
				// new SearchParticipant[] { SearchEngine
				// .getDefaultSearchParticipant() }, scope,
				// requestor, null);
				// } catch (CoreException e) {
				// // TODO Auto-generated catch block
				// e.printStackTrace();
				// }
				//
				// // select the ast node of the types
				// try {
				// System.out.println("num of compilation unit to parse: "
				// + compilationUnits.size() + type);
				// results.addAll(astModel.select(compilationUnits, type,
				// keyWord));
				// } catch (JavaModelException e) {
				// // TODO Auto-generated catch block
				// e.printStackTrace();
				// }
			}
		} else if (type.equals(JdtModel.CONSTRUCTOR_DEC)) {
			System.out.println("search constractor declaration: " + keyWord);

			// ArrayList<Object> tmpList = new ArrayList<Object>();
			// final ArrayList<ICompilationUnit> compilationUnits = new
			// ArrayList<ICompilationUnit>();

			// create search pattern for declarations of packages
			pattern = SearchPattern.createPattern(keyWord,
					IJavaSearchConstants.CONSTRUCTOR,
					IJavaSearchConstants.DECLARATIONS,
					SearchPattern.R_PATTERN_MATCH
							| SearchPattern.R_CASE_SENSITIVE);

			// create search requestor
			requestor = new SearchRequestor() {
				@Override
				public void acceptSearchMatch(SearchMatch match) {
					// Save the SearchMatch somewhere
					Object object = match.getElement();
					System.out.println(object.getClass() + " 123");
					IMethod temp = null;
					if (object instanceof IMethod) {
						temp = (IMethod) object;
						System.out.println(temp.getCompilationUnit()
								.getElementName());

						// avoid duplicate
						if (!compilationUnits.contains(temp
								.getCompilationUnit()))
							compilationUnits.add(temp.getCompilationUnit());

					}
				}
			};

			// create the search engine and start to search
			// SearchEngine engine = new SearchEngine();
			// try {
			// engine.search(pattern, new SearchParticipant[] { SearchEngine
			// .getDefaultSearchParticipant() }, scope, requestor,
			// null);
			// } catch (CoreException e) {
			// // TODO Auto-generated catch block
			// e.printStackTrace();
			// }
			//
			// // select the ast node of the types
			// try {
			// System.out.println("num of compilation unit to parse: "
			// + compilationUnits.size() + type);
			// results.addAll(astModel.select(compilationUnits, type, keyWord));
			// } catch (JavaModelException e) {
			// // TODO Auto-generated catch block
			// e.printStackTrace();
			// }
		} else if (type.equals(JdtModel.FIELD)) {
			System.out.println("search field declaration: " + keyWord);
			if (keyWord.equals("*")) {
				try {
					return astModel.getAllOfKind(type);
				} catch (JavaModelException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else {
				// ArrayList<Object> tmpList = new ArrayList<Object>();
				// final ArrayList<ICompilationUnit> compilationUnits = new
				// ArrayList<ICompilationUnit>();

				// create search pattern for declarations of packages
				pattern = SearchPattern.createPattern(keyWord,
						IJavaSearchConstants.FIELD,
						IJavaSearchConstants.DECLARATIONS,
						SearchPattern.R_PATTERN_MATCH
								| SearchPattern.R_CASE_SENSITIVE);

				// create search requestor
				requestor = new SearchRequestor() {
					@Override
					public void acceptSearchMatch(SearchMatch match) {
						// Save the SearchMatch somewhere
						Object object = match.getElement();
						System.out.println(object.getClass());
						IField temp = null;
						if (object instanceof IField) {
							temp = (IField) object;
							System.out.println(temp.getCompilationUnit()
									.getElementName());

							// avoid duplicate
							if (!compilationUnits.contains(temp
									.getCompilationUnit()))
								compilationUnits.add(temp.getCompilationUnit());

						}
					}
				};

				// create the search engine and start to search
				// SearchEngine engine = new SearchEngine();
				// try {
				// engine.search(pattern,
				// new SearchParticipant[] { SearchEngine
				// .getDefaultSearchParticipant() }, scope,
				// requestor, null);
				// } catch (CoreException e) {
				// // TODO Auto-generated catch block
				// e.printStackTrace();
				// }
				//
				// // select the ast node of the types
				// try {
				// System.out.println("num of compilation unit to parse: "
				// + compilationUnits.size() + type);
				// results.addAll(astModel.select(compilationUnits, type,
				// keyWord));
				// } catch (JavaModelException e) {
				// // TODO Auto-generated catch block
				// e.printStackTrace();
				// }
			}
		}

		// create the search engine and start to search
		SearchEngine engine = new SearchEngine();
		try {
			engine.search(pattern, new SearchParticipant[] { SearchEngine
					.getDefaultSearchParticipant() }, scope, requestor, null);
		} catch (CoreException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (isAST) {
			try {
//				System.out.println(names.size() + ":" + names.get(0));
				results.addAll(astModel.select(compilationUnits, type, keyWord));
			} catch (JavaModelException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return results;
	}

	static Object result = null;
	static ICompilationUnit compilationUnit = null;

	public void sebv() throws CoreException {

		// get workspace
		IWorkspace workspace = ResourcesPlugin.getWorkspace();
		IWorkspaceRoot root = workspace.getRoot();
		// get all projects in the workspace
		IProject[] projects = root.getProjects();
		List<IJavaProject> javaProjectList = new ArrayList<IJavaProject>();

		// find all java projects
		for (IProject project : projects) {
			if (project.isNatureEnabled("org.eclipse.jdt.core.javanature")
					&& project.isOpen()) {// if it's a java project and it's
											// open
				javaProjectList.add(JavaCore.create(project));
			}
		}

		List<IPackageFragment> packageList = new ArrayList<IPackageFragment>();

		IPackageFragment[] packages = null;
		ICompilationUnit[] sourceFiles = null;
		if (javaProjectList.size() > 0) { // if the java project list is not
											// empty
			packages = javaProjectList.get(0).getPackageFragments();
			if (packages.length > 0) // if the package array is not empty
				sourceFiles = packages[0].getCompilationUnits();

		}

		String keyWord = "get*";
		SearchPattern pattern = SearchPattern.createPattern(keyWord,
				IJavaSearchConstants.METHOD, IJavaSearchConstants.DECLARATIONS,
				SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CASE_SENSITIVE);

		IJavaProject[] javaProjects = javaProjectList
				.toArray(new IJavaProject[javaProjectList.size()]);
		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(
				javaProjects, IJavaSearchScope.SOURCES);

		// define a list to store the result
		final List<Object> results = new ArrayList<Object>();
		// create the collector of the result
		SearchRequestor requestor = new SearchRequestor() {
			@Override
			public void acceptSearchMatch(SearchMatch match) {
				// Save the SearchMatch somewhere
				Object object = match.getElement();
				IMethod temp = null;
				if (object instanceof IMethod) {
					temp = (IMethod) object;
					// save the result in the result list
					results.add(temp);
				}
			}
		};

		// create the search engine
		SearchEngine engine = new SearchEngine();
		// start to search
		engine.search(pattern, new SearchParticipant[] { SearchEngine
				.getDefaultSearchParticipant() }, scope, requestor, null);

	}

	public static Object searchOne(String type, ASTReflection astModel,
			List<IJavaProject> javaProjects, String keyWord, boolean isSource) {
		// TODO Auto-generated method stub
		System.out.println("Search One: " + keyWord);
		result = null;
		compilationUnit = null;

		boolean isAST = true;

		IJavaProject[] javaProjectsA = javaProjects
				.toArray(new IJavaProject[javaProjects.size()]);

		SearchPattern pattern = null;
		SearchRequestor requestor = null;

		// create search scope with the packages above and set only search
		// for source folders
		IJavaSearchScope scope;
		if (isSource) {
			scope = SearchEngine.createJavaSearchScope(javaProjectsA,
					IJavaSearchScope.SOURCES);
		} else {
			System.out.println("abc");
			scope = SearchEngine.createJavaSearchScope(javaProjectsA);
		}

		System.out.println("check type");
		if (type.equals(JdtModel.PACKAGE_DEC)) {
			isAST = false;
			// create search pattern for ONE package declaration
			pattern = SearchPattern.createPattern(keyWord,
					IJavaSearchConstants.PACKAGE,
					IJavaSearchConstants.DECLARATIONS,
					SearchPattern.R_PATTERN_MATCH
							| SearchPattern.R_CASE_SENSITIVE);

			// create search requestor
			requestor = new SearchRequestor() {
				@Override
				public void acceptSearchMatch(SearchMatch match) {
					// Save the SearchMatch somewhere
					Object object = match.getElement();

					// System.out.println(object.getClass());

					IPackageFragment temp = null;
					if (object instanceof IPackageFragment && result == null
							&& compilationUnit == null) {
						temp = (IPackageFragment) object;
						// System.out.println(temp.getElementName());
						// results.add(temp);
						result = temp;
					}
				}
			};

		} else if (type.equals(JdtModel.TYPE_DEC)) {
			System.out.println("search ONE type declaration: " + keyWord);

			// create search requestor
			requestor = new SearchRequestor() {
				@Override
				public void acceptSearchMatch(SearchMatch match) {
					// Save the SearchMatch somewhere
					Object object = match.getElement();
					// System.out.println(object.getClass());
					IType temp = null;
					if (object instanceof IType && result == null
							&& compilationUnit == null) {
						temp = (IType) object;
						System.out.println("NAME:"
								+ temp.getCompilationUnit().getElementName());
						// result = temp;
						// compilationUnits.add(temp.getCompilationUnit());
						compilationUnit = temp.getCompilationUnit();
					}
				}
			};
			// }

			// create search pattern for declarations of
			pattern = SearchPattern.createPattern(keyWord,
					IJavaSearchConstants.TYPE,
					IJavaSearchConstants.DECLARATIONS,
					SearchPattern.R_PATTERN_MATCH
							| SearchPattern.R_CASE_SENSITIVE);

		} else if (type.equals(JdtModel.METHOD_DEC)) {
			System.out.println("search ONE method declaration: " + keyWord);
			// if (keyWord.equals("*")) {
			// try {
			// return astModel.getAllOfKind(type);
			// } catch (JavaModelException e) {
			// // TODO Auto-generated catch block
			// e.printStackTrace();
			// }
			// } else {
			// ArrayList<Object> tmpList = new ArrayList<Object>();
			// = new ArrayList<ICompilationUnit>();

			// create search pattern for declarations of packages
			pattern = SearchPattern.createPattern(keyWord,
					IJavaSearchConstants.METHOD,
					IJavaSearchConstants.DECLARATIONS,
					SearchPattern.R_PATTERN_MATCH
							| SearchPattern.R_CASE_SENSITIVE);

			// create search requestor
			requestor = new SearchRequestor() {
				@Override
				public void acceptSearchMatch(SearchMatch match) {
					// Save the SearchMatch somewhere
					Object object = match.getElement();
					// System.out.println(object.getClass());
					IMethod temp = null;
					if (object instanceof IMethod && result == null
							&& compilationUnit == null) {
						temp = (IMethod) object;
						System.out.println(temp.getCompilationUnit()
								.getElementName());

						compilationUnit = temp.getCompilationUnit();

					}
				}
			};

		} else if (type.equals(JdtModel.CONSTRUCTOR_DEC)) {
			System.out
					.println("search ONE constractor declaration: " + keyWord);

			// create search pattern for declarations of packages
			pattern = SearchPattern.createPattern(keyWord,
					IJavaSearchConstants.CONSTRUCTOR,
					IJavaSearchConstants.DECLARATIONS,
					SearchPattern.R_PATTERN_MATCH
							| SearchPattern.R_CASE_SENSITIVE);

			// create search requestor
			requestor = new SearchRequestor() {
				@Override
				public void acceptSearchMatch(SearchMatch match) {
					// Save the SearchMatch somewhere
					Object object = match.getElement();
					System.out.println(object.getClass() + " 123");
					IMethod temp = null;
					if (object instanceof IMethod && result == null
							&& compilationUnit == null) {
						temp = (IMethod) object;
						System.out.println(temp.getCompilationUnit()
								.getElementName());

						// avoid duplicate
						// if (!compilationUnits.contains(temp
						// .getCompilationUnit()))
						// compilationUnits.add(temp.getCompilationUnit());
						compilationUnit = temp.getCompilationUnit();

					}
				}
			};

		} else if (type.equals(JdtModel.FIELD)) {
			System.out.println("search ONE field declaration: " + keyWord);

			// create search pattern for declarations of packages
			pattern = SearchPattern.createPattern(keyWord,
					IJavaSearchConstants.FIELD,
					IJavaSearchConstants.DECLARATIONS,
					SearchPattern.R_PATTERN_MATCH
							| SearchPattern.R_CASE_SENSITIVE);

			// create search requestor
			requestor = new SearchRequestor() {
				@Override
				public void acceptSearchMatch(SearchMatch match) {
					// Save the SearchMatch somewhere
					Object object = match.getElement();
					System.out.println(object.getClass());
					IField temp = null;
					if (object instanceof IField && result == null
							&& compilationUnit == null) {
						temp = (IField) object;
						System.out.println(temp.getCompilationUnit()
								.getElementName());

						// avoid duplicate
						// if (!compilationUnits.contains(temp
						// .getCompilationUnit()))
						// compilationUnits.add(temp.getCompilationUnit());
						compilationUnit = temp.getCompilationUnit();

					}
				}
			};

		}

		// create the search engine and start to search
		SearchEngine engine = new SearchEngine();
		try {
			engine.search(pattern, new SearchParticipant[] { SearchEngine
					.getDefaultSearchParticipant() }, scope, requestor, null);
		} catch (CoreException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (isAST) {
			try {
				// results.addAll(astModel.select(compilationUnits, type,
				// keyWord));
				System.out.println("SEARCH AST:"
						+ compilationUnit.getElementName());
				result = astModel.selectOne(compilationUnit, type, keyWord);
			} catch (JavaModelException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return result;
	}

}
